/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */

#include "drv_spi.h"
#include "pwm3901_polling.h"
#include "zino.h"
#define DBG_TAG "dev_3901"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#define PMW3901_BUS_NAME "spi_pmw"
#define PMW3901_NRESET_PIN PD2    // PC10, needs to be asserted (hold low) for at least 100ns
#define PMW3901_P_MOTION_PIN PC12 // PA15, active low when motion has occurred

pmw3901mb_handle_t pwm3201_dev;
spi_dev_t pmw_spi = {
    .cs_pin = PMW_CSN_PIN,
    .mode = RT_SPI_MODE_0 | RT_SPI_MSB,
    .data_width = 8,
    .max_hz = 20 * 1000 * 1000,
};

pmw3901mb_motion_t pmw3901_motion;

/**
 * @brief  interface spi bus init
 * @return status code
 *         - 0 success
 *         - 1 spi init failed
 * @note   none
 */
uint8_t pmw3901mb_interface_spi_init(void)
{
    return 0;
}
/**
 * @brief  interface spi bus deinit
 * @return status code
 *         - 0 success
 *         - 1 spi deinit failed
 * @note   none
 */
uint8_t pmw3901mb_interface_spi_deinit(void)
{
    // gs_bus = 0;
    return 0;
}
/**
 * @brief      interface spi bus read
 * @param[in]  reg is the register address
 * @param[out] *buf points to a data buffer
 * @param[in]  len is the length of data buffer
 * @return     status code
 *             - 0 success
 *             - 1 read failed
 * @note       none
 */
uint8_t pmw3901mb_interface_spi_read(uint8_t reg, uint8_t *buf, uint16_t len)
{
    spi_send_then_receive(&pmw_spi, &reg, 1, buf, len);
    return RT_EOK;
}
/**
 * @brief     interface spi bus write
 * @param[in] reg is the register address
 * @param[in] *buf points to a data buffer
 * @param[in] len is the length of data buffer
 * @return    status code
 *            - 0 success
 *            - 1 write failed
 * @note      none
 */
uint8_t pmw3901mb_interface_spi_write(uint8_t reg, uint8_t *buf, uint16_t len)
{
    spi_send_then_send(&pmw_spi, &reg, 1, buf, len);
    return RT_EOK;
}
/**
 * @brief  interface reset gpio init
 * @return status code
 *         - 0 success
 *         - 1 init failed
 * @note   none
 */
uint8_t pmw3901mb_interface_reset_gpio_init(void)
{
    pin_mode(PMW3901_NRESET_PIN, PIN_MODE_OUTPUT_PP);
    pin_write(PMW3901_NRESET_PIN, 1);
    return RT_EOK;
}

/**
 * @brief  interface reset gpio deinit
 * @return status code
 *         - 0 success
 *         - 1 deinit failed
 * @note   none
 */
uint8_t pmw3901mb_interface_reset_gpio_deinit(void)
{
    return 0;
}
/**
 * @brief     interface reset gpio write
 * @param[in] data is the written data
 * @return    status code
 *            - 0 success
 *            - 1 write failed
 * @note      none
 */
uint8_t pmw3901mb_interface_reset_gpio_write(uint8_t data)
{
    pin_write(PMW3901_NRESET_PIN, data);
    return (pin_read(PMW3901_NRESET_PIN) == data ? 0 : 1);
}
/**
 * @brief     interface delay ms
 * @param[in] ms
 * @note      none
 */
void pmw3901mb_interface_delay_ms(uint32_t ms)
{
    rt_thread_delay(ms);
}
/**
 * @brief     interface print format data
 * @param[in] fmt is the format data
 * @note      none
 */
void pmw3901mb_interface_debug_print(const char *const fmt, ...)
{
    // char str[128];
    // va_list args;

    // memset((char*)str, 0, sizeof(char) * 128);
    // va_start(args, fmt);
    // rt_vsnprintf((char*)str, 128, (char const*)fmt, args);
    // va_end(args);

    // rt_kprintf("%s", str);
}
uint8_t pmw3901_init(pmw3901mb_handle_t *gs)
{
    uint8_t ret;
    DRIVER_PMW3901MB_LINK_INIT(gs, pmw3901mb_handle_t);
    DRIVER_PMW3901MB_LINK_SPI_INIT(gs, pmw3901mb_interface_spi_init);
    DRIVER_PMW3901MB_LINK_SPI_DEINIT(gs, pmw3901mb_interface_spi_deinit);
    DRIVER_PMW3901MB_LINK_SPI_READ(gs, pmw3901mb_interface_spi_read);
    DRIVER_PMW3901MB_LINK_SPI_WRITE(gs, pmw3901mb_interface_spi_write);
    DRIVER_PMW3901MB_LINK_RESET_GPIO_INIT(gs, pmw3901mb_interface_reset_gpio_init);
    DRIVER_PMW3901MB_LINK_RESET_GPIO_DEINIT(gs, pmw3901mb_interface_reset_gpio_deinit);
    DRIVER_PMW3901MB_LINK_RESET_GPIO_WRITE(gs, pmw3901mb_interface_reset_gpio_write);
    DRIVER_PMW3901MB_LINK_DELAY_MS(gs, pmw3901mb_interface_delay_ms);
    DRIVER_PMW3901MB_LINK_DEBUG_PRINT(gs, pmw3901mb_interface_debug_print);

    // rt_kprintf("pmw3901_init...");
    // gs_handle.debug_print("hellow\n");
    ret = pmw3901mb_init(gs);
    pin_mode(PMW3901_P_MOTION_PIN, PIN_MODE_INPUT_PULLUP);
    if (ret == 0)
    {
        LOG_I("pmw3901mb_init success");

        /* chip power up */
        ret = pmw3901mb_power_up(gs);
        LOG_I("pmw3901mb_power_up success");
        /* set optimum performance */
        ret = pmw3901mb_set_optimum_performance(gs);
        LOG_I("pmw3901mb_set_optimum_performance success");
        // pmw3901mb_motion_t motion;

        // while (1)
        // {
        //     pmw3901mb_burst_read(gs, &motion);
        //     rt_kprintf("motion x:%03d, y:%03d, is:%d obs:%d avg:%d shut:%d qua:%d\n", motion.delta_x, motion.delta_y, motion.is_valid,
        //         motion.observation,
        //         motion.raw_average,
        //         motion.shutter,
        //         motion.surface_quality
        //     );
        //     rt_thread_delay(10);
        // }
    }
    // rt_kprintf("\nRet%d \n",ret);
    return ret;
}
uint8_t pmw3901_read_data(pmw3901mb_motion_t *motion)
{

    return pmw3901mb_burst_read(&pwm3201_dev, motion);
}

void pwm3901_update_1ms(void)
{
    static uint8_t motion_cnt = 0;
    static uint32_t dt = 0;
    if (pin_read(PMW3901_P_MOTION_PIN) == 0)
    {
        motion_cnt++;
        int8_t ret = pmw3901mb_burst_read(&pwm3201_dev, &pmw3901_motion);
        if(ret != 0 || pmw3901_motion.is_valid != 1)
        {
            memset(&pmw3901_motion, 0, sizeof(pmw3901mb_motion_t));
        }
    }
    if (millis() >= (dt + 1000))
    {
        LOG_I("motion cnt:%d", motion_cnt);
        motion_cnt = 0;
        dt = millis();
    }
}

int pwm3901_dev_init(void)
{
    return pmw3901_init(&pwm3201_dev);
}
